package timit;

import java.io.*;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;

/**
 * Created with IntelliJ IDEA.
 * User: lahiru
 * Date: 6/13/14
 * Time: 10:30 AM
 * To change this template use File | Settings | File Templates.
 *
 * revision 6 has the code for .arff file generation for clustering
 */
public class HUSpeakerPhnDist {
    private static final int numberOfLayers = 6;
    private static final String hiddenActivationDir = "/home/lahiru/experiments/Speaker-effects/activations/train/";
    private static final String pdfAlignmentsDir = "/home/lahiru/experiments/Speaker-effects/alignments/";
    //    private static final String saveObjects = "/home/lahiru/experiments/Speaker-effects/objects/train/";
//    private static final String listOfSpeakers = "FCAL1 FDMS0 MBNS0 MRTK0";
    private static final String listOfSpeakers = "FALK0 FALR0 FBCG1 FBCH0 FBJL0 FCDR1 FCEG0 FCKE0 FCMM0 FDFB0 MCAE0 " +
            "MCAL0 MCHL0 MCSS0 MCTH0 MCTM0 MDBP0 MDCD0 MDHS0 MDLC2";
    //    private static final String listOfSpeakers = "FALK0";
    private static final int numberOfHiddenUnits=1024;
    private static final int pdfCount = 183;
    private static final String haVectorDirectory = "/home/lahiru/experiments/Speaker-effects/plots/speakerSil/train/hiddenLayer";
    private static final String datDirectory = "/home/lahiru/experiments/Speaker-effects/plots/speakerSil/train/";
    //    private static final int pdfIDforStats = 1;
    private static final double threshold = 0.2;

    public static void main(String[] args) {
        List<String> speakers = (Arrays.asList(listOfSpeakers.split(" ")));
        int numSpeakers = speakers.size();

        List<Integer> finalSNs = new ArrayList<Integer>();
        for(int temp=0; temp<numberOfHiddenUnits; temp++){
            finalSNs.add(temp);
        }

        for (int pdfIDforStats=3; pdfIDforStats<pdfCount; pdfIDforStats++){
            List<Integer> intSNs = new ArrayList<Integer>();

            for (int i = 5; i <= numberOfLayers; i++) {                    //Only analyze the final hidden layer for now
//                System.out.println(" Start processing the layer " + i);

                Map<Integer,Integer> spkCountMap = new HashMap<Integer, Integer>(numSpeakers);
                for(int j=0; j<numSpeakers; j++){  //initialize the scounts map
                    spkCountMap.put(j,0);
                }

                Map<Integer,List<Double>> huMap = new HashMap<Integer, List<Double>>(numberOfHiddenUnits);
                for(int j=0; j<numberOfHiddenUnits; j++){
                    List<Double> tempList = new ArrayList<Double>(numSpeakers);
                    for(int k=0; k<numSpeakers; k++){
                        tempList.add(0.0);
                    }
                    huMap.put(j,tempList);
                }

                int totalFrameCount = 0;
                int speakerId=0;

                for(String spk:speakers){
                    int finalFrameCount = 0;

                    String ha = hiddenActivationDir + "h" + i + "/activations_" + spk + ".ark";
                    String pAlignments = pdfAlignmentsDir + "pdf." + spk +".ark";

//                System.out.println(" Reading the activation file  " + ha + " for the speaker " + spk);
                    //Read pdf-alignments line by line, file contains a line per utterance.

                    try {

                        BufferedReader phonesBr = new BufferedReader(new FileReader(pAlignments));
                        String line;

                        BufferedReader haBr = new BufferedReader(new FileReader(ha));
                        String line1;

                        int utteranceCount = 0;
                        int frameCount = 0;
                        String frameUtterance = "";
                        String utterance = "";

                        while ((line = phonesBr.readLine()) != null) {
                            String phoneIds[] = line.split(" ");
                            utterance = phoneIds[0];

                            while ((line1 = haBr.readLine()) != null) {

                                String hArray[] = line1.trim().split(" ");

                                if (hArray.length == 3) {  //starting of an utterance
                                    utteranceCount = utteranceCount + 1;
                                    frameCount = 0;
                                    frameUtterance = hArray[0];

                                    String tempArray[] = null;
                                    String line2 = "";

                                    if (!frameUtterance.equalsIgnoreCase(utterance)) {
                                        System.err.println("The frame utterance " + frameUtterance);
                                        System.err.println("The phone utterance " + utterance);

                                        do {
                                            line2 = haBr.readLine();
                                            tempArray = line2.trim().split(" ");

                                        } while (tempArray.length != 3);

                                        System.err.println("The new frame utterance is " + tempArray[0]);
                                        //write about attributes

                                    }

                                } else if (hArray.length == numberOfHiddenUnits) {  //intermediate frame
                                    int pdfId = Integer.parseInt(phoneIds[frameCount + 1]);
                                    if (pdfId==pdfIDforStats){
                                        spkCountMap.put(speakerId, spkCountMap.get(speakerId)+1);


                                        for(int p=0; p<numberOfHiddenUnits;p++){
                                            List<Double> tmpList = huMap.get(p);
                                            tmpList.add(speakerId, tmpList.remove(speakerId)+Double.parseDouble(hArray[p]));
                                            huMap.put(p,tmpList);
                                        }
                                    }


                                    frameCount = frameCount + 1;
                                } else if (hArray.length == numberOfHiddenUnits + 1) {   //last frame of the utterance
                                    int pdfId = Integer.parseInt(phoneIds[frameCount + 1]);
                                    if (pdfId==pdfIDforStats){
                                        spkCountMap.put(speakerId, spkCountMap.get(speakerId)+1);

                                        for(int p=0; p<numberOfHiddenUnits;p++){
                                            List<Double> tmpList = huMap.get(p);
                                            tmpList.add(speakerId, tmpList.remove(speakerId)+Double.parseDouble(hArray[p]));
                                            huMap.put(p,tmpList);
                                        }
                                    }

                                    frameCount = frameCount + 1;
                                    finalFrameCount = finalFrameCount + frameCount;
                                    break;
                                } else {
                                    System.err.println("This is not possible " + hArray.length);
                                }
                            }

                        }
                        haBr.close();
                        totalFrameCount = totalFrameCount + finalFrameCount;
                        speakerId = speakerId + 1;
                        phonesBr.close();
                    } catch (IOException e) {
                        e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
                    }
                }


                try {
//                    FileWriter fileWriter = new FileWriter(haVectorDirectory + i + ".dat");
//                    BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);

                    double totalDistance = 0.0;
                    for (int j=0; j<numberOfHiddenUnits; j++){

//                        FileWriter fileWriter1 = new FileWriter(datDirectory+"h"+i+"/" + j + ".dat");
//                        BufferedWriter bufferedWriter1 = new BufferedWriter(fileWriter1);

                        List<Double> tempList = huMap.get(j);
                        List<Double> activationVector = new ArrayList<Double>(numSpeakers);
                        for (int p = 0; p < numSpeakers; p++) {
                            double value = tempList.get(p);
                            int count = spkCountMap.get(p);
//                        double finalvalue = (value/count);
                            NumberFormat formatter = new DecimalFormat("###.###############");
                            double intFinalVal = 0.0;
                            if (count != 0){                         //Avoid deviding by zero
                                intFinalVal = value/count;
                            }

                            String finalvalue = formatter.format(intFinalVal);
                            activationVector.add(intFinalVal);
//                            bufferedWriter1.write(finalvalue+"\n");
                        }
                        double distance = HUDist.calKLDistance(activationVector);
                        totalDistance = totalDistance + distance;
                        NumberFormat formatter = new DecimalFormat("###.###############");
                        if(distance > threshold){
                            intSNs.add(j);
                        }
//                        bufferedWriter.write(formatter.format(distance)+"\n");
//                        bufferedWriter1.close();

                    }
//                    System.out.println("The total distance for layer " + i + " is " + totalDistance);
//                    bufferedWriter.close();
//                } catch (IOException e) {
                } catch (Exception e) {
                    e.printStackTrace();
                }


            }
          //keep the intersection between finalSNs and intSNs
          finalSNs = intersection(finalSNs,intSNs);
            System.out.println("The size of the finalSNs " + finalSNs.size());
        }
        System.out.println("The final size of the finalSNs " + finalSNs.size());
        for(Integer t : finalSNs){
            System.out.println(t);
        }
    }

    private static List<Integer> intersection(List<Integer> list1, List<Integer> list2) {
        List<Integer> list = new ArrayList<Integer>();

        for (Integer t : list1) {
            if(list2.contains(t)) {
                list.add(t);
            }
        }

        return list;
    }
}
